<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="icon" href="favicon.ico" />
    <title>Navigation Guards demo</title>
  </head>
  <body>
    <script type="text/javascript" src="./common.js"></script>
    <script src="https://unpkg.com/vue@2.7/dist/vue.js"></script>
    <script src="https://unpkg.com/vue-router@3/dist/vue-router.js"></script>
    <link type="text/css" rel="stylesheet" href="style.css" />
    <div id="app">
      <router-link to="/">To Home</router-link>
      <router-link to="/sub/cc">To Child1</router-link>
      <router-link to="/sub/cd?a=000">To Child2</router-link>
      <router-link to="/dd?b=2">To Child1</router-link>
      <router-link to="/e?b=2">To NotFound</router-link>
      <router-view></router-view>
    </div>
    <!-- flower -->
    <script type="text/javascript">
      const template = `
        <div>
          <p>name:{{$route.name}}</p>
          <p>path:{{$route.path}}</p>
          <p>params:{{$route.params}}</p>
          <p>query:{{$route.query}}</p>
        </div>
        `;
      const Home = {
        template: template,
        beforeRouteEnter(to, from, next) {
          log("beforeRouteEnter", to, from);
          next();
          // 在渲染该组件的对应路由被 confirm 前调用
          // 不！能！获取组件实例 `this`
          // 因为当守卫执行前，组件实例还没被创建
        },
        beforeRouteUpdate(to, from, next) {
          log("beforeRouteUpdate", to, from);
          next();
          // 在当前路由改变，但是该组件被复用时调用
          // 举例来说，对于一个带有动态参数的路径 /foo/:id，在 /foo/1 和 /foo/2 之间跳转的时候，
          // 由于会渲染同样的 Foo 组件，因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
          // 可以访问组件实例 `this`
        },
        beforeRouteLeave(to, from, next) {
          log("beforeRouteLeave", to, from);
          next();
          // 导航离开该组件的对应路由时调用
          // 可以访问组件实例 `this`
        },
      };
      const Child = {
        template: `
          <div>
            <span>Sub main</span>
            <router-view></router-view>
          </div>`,
      };
      const Child1 = {
        template: template,
        beforeRouteEnter(to, from, next) {
          log("beforeRouteEnter", to, from);
          next();
          // 在渲染该组件的对应路由被 confirm 前调用
          // 不！能！获取组件实例 `this`
          // 因为当守卫执行前，组件实例还没被创建
        },
        beforeRouteUpdate(to, from, next) {
          log("beforeRouteUpdate", to, from);
          next();
          // 在当前路由改变，但是该组件被复用时调用
          // 举例来说，对于一个带有动态参数的路径 /foo/:id，在 /foo/1 和 /foo/2 之间跳转的时候，
          // 由于会渲染同样的 Foo 组件，因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
          // 可以访问组件实例 `this`
        },
        beforeRouteLeave(to, from, next) {
          log("beforeRouteLeave", to, from);
          next();
          // 导航离开该组件的对应路由时调用
          // 可以访问组件实例 `this`
        },
      };
      const Child2 = { template: template };
      const NotFound = { template };

      const routes = [
        {
          path: "*",
          component: NotFound,
        },
        {
          path: "/",
          name: "Home",
          component: Home,
          beforeEnter: (to, form, next) => {
            log("Per-Route Guard", to, form);
            // 此处不调用 next()，路由不会继续导航
            next();
          },
        },
        {
          path: "/dd",
          name: "outer child path /dd",
          component: Child1,
        },
        {
          path: "/sub",
          name: "Child",
          component: Child,
          children: [
            {
              path: "cc",
              name: "Child_1",
              component: Child1,
            },
            {
              path: "cd",
              name: "Child_2",
              component: Child2,
            },
          ],
        },
      ];
      const router = new VueRouter({
        routes,
      });
      router.beforeEach((to, form, next) => {
        log("Global Before Guards", to, "\n", form);
        const path = to.path;
        // 进行管道中的下一个钩子。如果全部钩子执行完了，则导航的状态就是 confirmed (确认的)。
        next();
        // 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮)，那么 URL 地址会重置到 from 路由对应的地址。
        // next(false);
        // 跳转到一个不同的地址。当前的导航被中断，然后进行一个新的导航。你可以向 next 传递任意位置对象，且允许设置诸如 replace: true、name: 'home'
        // 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
        // next({ path: "/dd" });->无限迭代，内存溢出
        // (path.includes("sub") || next("/sub/cc")) && next(); //不是child2的所有路由去child1
        // 如果传入 next 的参数是一个 Error 实例，则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
        // next(new Error("ddd"));
      });
      router.beforeResolve((to, form, next) => {
        const path = to.path;
        log("Global Resolve Guards", to, "\n", form);
        // 不会导航出页面
        // next(false);
        // (path.includes("sub") || next("/sub/cc")) && next(); //不是child2的所有路由去child1
        next();
      });
      // global after hooks,不会接受 next 函数也不会改变导航本身：
      router.afterEach((to, form) => {
        log("Global After Hooks", to, "\n", form);
      });
      const app = new Vue({
        el: "#app",
        router,
      });
      /**
       * 完整的导航解析流程
       * 导航被触发。
       * 在失活的组件里调用 beforeRouteLeave 守卫。
       * 调用全局的 beforeEach 守卫。在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
       * 在路由配置里调用 beforeEnter。
       * 解析异步路由组件。
       * 在被激活的组件里调用 beforeRouteEnter。
       * 调用全局的 beforeResolve 守卫 (2.5+)。
       * 导航被确认。
       * 调用全局的 afterEach 钩子。
       * 触发 DOM 更新。
       * 调用 beforeRouteEnter 守卫中传给 next 的回调函数，创建好的组件实例会作为回调函数的参数传入。
       * /
    </script>
  </body>
</html>
